home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / Direct3D / Water / CWater.cpp < prev    next >
C/C++ Source or Header  |  2001-10-08  |  16KB  |  634 lines

  1. //
  2. // CWater
  3. // Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
  4. //
  5.  
  6. #include <d3dx8.h>
  7. #include "CWater.h"
  8.  
  9. #define WATER_SHIFT 6
  10. #define WATER_SIZE  (1 << WATER_SHIFT)
  11. #define WATER_AREA  (WATER_SIZE * WATER_SIZE)
  12. #define WATER_MASK  (WATER_SIZE - 1)
  13.  
  14. #define WATER_SPHERE_HEIGHT   20.0f
  15. #define WATER_SPHERE_RADIUS2  (35.0f * 35.0f)
  16.  
  17. #define WATER_INDEX(x, y) \
  18.     ((x) | ((y) << WATER_SHIFT))
  19.  
  20. #define WATER_INDEX_WRAP(x, y) \
  21.     (((x) & WATER_MASK) | (((y) & WATER_MASK) << WATER_SHIFT))
  22.  
  23.  
  24. #if defined(_X86) && !defined(_WIN64)
  25. inline int f2i(float flt) 
  26. {
  27.     volatile int n; 
  28.  
  29.     __asm 
  30.     {
  31.         fld flt
  32.         fistp n
  33.     }
  34.  
  35.     return n;
  36. }
  37. #else
  38. inline int f2i(float flt) 
  39. {
  40.     return (int) flt;
  41. }
  42. #endif
  43.  
  44.  
  45.  
  46. //////////////////////////////////////////////////////////////////////////////
  47. // Types /////////////////////////////////////////////////////////////////////
  48. //////////////////////////////////////////////////////////////////////////////
  49.  
  50. #pragma pack(1)
  51. typedef struct WATER_VERTEX
  52. {
  53.     D3DXVECTOR3 m_vecPos;
  54.     D3DXVECTOR3 m_vecNormal;
  55.     D3DCOLOR    m_dwDiffuse;
  56.     D3DXVECTOR2 m_vecTex;
  57.  
  58. } WATER_VERTEX;
  59.  
  60. #define WATER_FVF   (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0))
  61.  
  62.  
  63. typedef struct CAUSTICS_VERTEX
  64. {
  65.     D3DXVECTOR3 m_vecPos;
  66.     D3DCOLOR    m_dwDiffuse;
  67.  
  68. } CAUSTICS_VERTEX;
  69.  
  70. #define CAUSTICS_FVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)
  71. #pragma pack()
  72.  
  73.  
  74. //////////////////////////////////////////////////////////////////////////////
  75. // CWater implementation /////////////////////////////////////////////////////
  76. //////////////////////////////////////////////////////////////////////////////
  77.  
  78. CWater::CWater()
  79. {
  80.     m_fDepth    = 0.0f;
  81.     m_fScaleTex = 1.0f;
  82.  
  83.     m_uIndices  = 0;
  84.     m_uVertices = 0;
  85.  
  86.     m_pRefract     = NULL;
  87.     m_pSurface     = NULL;
  88.  
  89.     m_pDevice      = NULL;
  90.     m_pibIndices   = NULL;
  91.     m_pvbVertices  = NULL;
  92.     m_pvbCaustics  = NULL;
  93. }
  94.  
  95.  
  96. CWater::~CWater()
  97. {
  98.     if(m_pSurface)
  99.         delete [] m_pSurface;
  100. }
  101.  
  102.  
  103. HRESULT
  104. CWater::Initialize(float fSize, float fDepth)
  105. {
  106.     m_fSize = fSize;
  107.     m_fDepth = fDepth;
  108.     m_fScaleTex = 1.0f / fSize;
  109.  
  110.     // Calculate number of vertices and indices
  111.     m_uVertices = WATER_AREA;
  112.     m_uIndices  = m_uVertices * 2;
  113.  
  114.  
  115.  
  116.     // Create refraction table
  117.     static WATER_REFRACT Refract[512];
  118.  
  119.     if(!m_pRefract)
  120.     {
  121.         m_pRefract = &Refract[256];
  122.  
  123.         for(UINT u = 0; u < 256; u++)
  124.         {        
  125.             float fCos0 = (float) u / (float) 256.0f;
  126.             float f0 = acosf(fCos0);
  127.             float fSin0 = sinf(f0);
  128.  
  129.             float fSin1 = fSin0 / 1.333f; // water
  130.             float f1 = asinf(fSin1);
  131.             float fCos1 = cosf(f1);
  132.         
  133.             m_pRefract[u].fRefract = fSin0 / fSin1 * fCos1 - fCos0;
  134.             m_pRefract[u].fRefractNorm = - fSin1 / fSin0;
  135.             m_pRefract[u].dwDiffuse = ((((0xff - u)*(0xff - u)*(0xff - u)) << 8) & 0xff000000);
  136.  
  137.             Refract[u] = Refract[256];
  138.         }
  139.     }
  140.  
  141.  
  142.  
  143.     // Create maps
  144.     if(!m_pSurface)
  145.     {
  146.         if(!(m_pSurface = new WATER_SURFACE[WATER_AREA]))
  147.             return E_OUTOFMEMORY;
  148.  
  149.         memset(m_pSurface, 0x00, WATER_AREA * sizeof(WATER_SURFACE));
  150.     }
  151.  
  152.     return S_OK;
  153. }
  154.  
  155.  
  156.  
  157. HRESULT
  158. CWater::OnCreateDevice(IDirect3DDevice8 *pDevice)
  159. {
  160.     m_pDevice = pDevice;
  161.     return S_OK;
  162. }
  163.  
  164.  
  165. HRESULT
  166. CWater::OnResetDevice()
  167. {
  168.     HRESULT hr;
  169.  
  170.     // Create indices
  171.     if(!m_pibIndices)
  172.     {
  173.         WORD *pwIndices;
  174.  
  175.         if(FAILED(hr = m_pDevice->CreateIndexBuffer(m_uIndices * sizeof(WORD), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &m_pibIndices)))
  176.             return hr;
  177.  
  178.         if(FAILED(hr = m_pibIndices->Lock(0, m_uIndices * sizeof(WORD), (BYTE**) &pwIndices, 0)))
  179.             return hr;
  180.  
  181.  
  182.         // Fill in indicies
  183.         UINT uX = 0, uZ = 0;
  184.         WORD *pwIndex = pwIndices;
  185.  
  186.         for(UINT uSize = WATER_SIZE; uSize != 0; uSize -= 2)
  187.         {
  188.             UINT u;
  189.  
  190.             // Top
  191.             for(u = 0; u < uSize; u++)
  192.             {
  193.                 *pwIndex++ = uX + uZ * WATER_SIZE;
  194.                 *pwIndex++ = uX + uZ * WATER_SIZE + WATER_SIZE;
  195.                 uX++;
  196.             }
  197.  
  198.             uX--;
  199.             uZ++;
  200.  
  201.  
  202.             // Right
  203.             for(u = 1; u < uSize; u++)
  204.             {
  205.                 *pwIndex++ = uX + uZ * WATER_SIZE;
  206.                 *pwIndex++ = uX + uZ * WATER_SIZE - 1;
  207.                 uZ++;
  208.             }
  209.  
  210.             uZ--;
  211.             uX--;
  212.  
  213.  
  214.             // Bottom
  215.             for(u = 1; u < uSize; u++)
  216.             {
  217.                 *pwIndex++ = uX + uZ * WATER_SIZE;
  218.                 *pwIndex++ = uX + uZ * WATER_SIZE - WATER_SIZE;
  219.                 uX--;
  220.             }
  221.  
  222.             uX++;
  223.             uZ--;
  224.  
  225.  
  226.             // Left
  227.             for(u = 2; u < uSize; u++)
  228.             {
  229.                 *pwIndex++ = uX + uZ * WATER_SIZE;
  230.                 *pwIndex++ = uX + uZ * WATER_SIZE + 1;
  231.                 uZ--;
  232.             }
  233.  
  234.             uZ++;
  235.             uX++;
  236.         }
  237.  
  238.         for(pwIndex = pwIndices; pwIndex < pwIndices + m_uIndices; pwIndex++)
  239.         {
  240.             if(*pwIndex >= m_uVertices)
  241.                 *pwIndex = 0;
  242.         }
  243.  
  244.         m_pibIndices->Unlock();
  245.     }
  246.  
  247.     
  248.     // Create vertices
  249.     if(!m_pvbVertices)
  250.     {
  251.         if(FAILED(hr = m_pDevice->CreateVertexBuffer(m_uVertices * sizeof(WATER_VERTEX), 
  252.             D3DUSAGE_DYNAMIC, WATER_FVF, D3DPOOL_DEFAULT, &m_pvbVertices)))
  253.         {
  254.             return hr;
  255.         }
  256.     }
  257.  
  258.  
  259.     // Create caustics
  260.     if(!m_pvbCaustics)
  261.     {
  262.         if(FAILED(hr = m_pDevice->CreateVertexBuffer(m_uVertices * sizeof(CAUSTICS_VERTEX), 
  263.             D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, CAUSTICS_FVF, D3DPOOL_DEFAULT, &m_pvbCaustics)))
  264.         {
  265.             return hr;
  266.         }
  267.     }
  268.  
  269.     return S_OK;
  270. }
  271.  
  272. HRESULT
  273. CWater::OnLostDevice()
  274. {
  275.     if(m_pibIndices)
  276.     {
  277.         m_pibIndices->Release();
  278.         m_pibIndices = NULL;
  279.     }
  280.  
  281.     if(m_pvbVertices)
  282.     {
  283.         m_pvbVertices->Release();
  284.         m_pvbVertices = NULL;
  285.     }
  286.  
  287.     if(m_pvbCaustics)
  288.     {
  289.         m_pvbCaustics->Release();
  290.         m_pvbCaustics = NULL;
  291.     }
  292.  
  293.     return S_OK;
  294. }
  295.  
  296. HRESULT
  297. CWater::OnDestroyDevice()
  298. {
  299.     m_pDevice = NULL;
  300.     return S_OK;
  301. }
  302.  
  303.  
  304.  
  305. HRESULT
  306. CWater::Drop()
  307. {
  308.     UINT uX = rand();
  309.     UINT uY = rand();
  310.  
  311.     m_pSurface[WATER_INDEX_WRAP(uX, uY)].fVelocity -= 0.25f;
  312.  
  313.     m_pSurface[WATER_INDEX_WRAP(uX - 1, uY)].fVelocity -= 0.125f;
  314.     m_pSurface[WATER_INDEX_WRAP(uX + 1, uY)].fVelocity -= 0.125f;
  315.     m_pSurface[WATER_INDEX_WRAP(uX, uY - 1)].fVelocity -= 0.125f;
  316.     m_pSurface[WATER_INDEX_WRAP(uX, uY + 1)].fVelocity -= 0.125f;
  317.  
  318.     m_pSurface[WATER_INDEX_WRAP(uX - 1, uY - 1)].fVelocity -= 0.0625f;
  319.     m_pSurface[WATER_INDEX_WRAP(uX + 1, uY + 1)].fVelocity -= 0.0625f;
  320.     m_pSurface[WATER_INDEX_WRAP(uX + 1, uY - 1)].fVelocity -= 0.0625f;
  321.     m_pSurface[WATER_INDEX_WRAP(uX - 1, uY + 1)].fVelocity -= 0.0625f;
  322.  
  323.     return S_OK;
  324. }
  325.  
  326.  
  327. HRESULT
  328. CWater::Update(D3DXVECTOR3 &vecPos, D3DXVECTOR3 &vecLight, BOOL bCalcCaustics)
  329. {
  330.     HRESULT hr;
  331.     UINT uXN, uX, uXP, uY, uYN, uY0, uYP;
  332.  
  333.  
  334.     // Compute desired height
  335.     m_fAvgHeight = 0.0f;
  336.     WATER_SURFACE *pSurface = m_pSurface;
  337.  
  338.  
  339.  
  340.     uYN  = WATER_AREA - WATER_SIZE;
  341.     uY0  = 0;
  342.     uYP  = WATER_SIZE;
  343.  
  344.     do
  345.     {
  346.         uXN  = WATER_SIZE - 1;
  347.         uX   = 0;
  348.         uXP  = 1;
  349.  
  350.         do
  351.         {
  352.             // Bowl
  353.             float fX = (float) uX - (WATER_SIZE >> 1);
  354.             float fZ = (float) (uY0 >> WATER_SHIFT) - (WATER_SIZE >> 1);
  355.             float fDesire;
  356.  
  357.             if((fX * fX + fZ * fZ) < (WATER_SPHERE_RADIUS2 -  WATER_SPHERE_HEIGHT * WATER_SPHERE_HEIGHT))
  358.             {
  359.                 fDesire = 
  360.                      (m_pSurface[uXN + uYN].fHeight + 
  361.                       m_pSurface[uXP + uYN].fHeight + 
  362.                       m_pSurface[uXN + uYP].fHeight + 
  363.                       m_pSurface[uXP + uYP].fHeight) * (1.0f / 12.0f)
  364.                       +
  365.                      (m_pSurface[uX  + uYN].fHeight +
  366.                       m_pSurface[uXN + uY0].fHeight +
  367.                       m_pSurface[uXP + uY0].fHeight +
  368.                       m_pSurface[uX  + uYP].fHeight) * (2.0f / 12.0f);
  369.             }
  370.             else
  371.             {
  372.                 fDesire = 0.0f;
  373.                 pSurface->fHeight = 0.0f;
  374.                 pSurface->fVelocity = 0.0f;
  375.             }
  376.  
  377.  
  378.             // Update velocity
  379.             if(pSurface->fVelocity > 0.01f || pSurface->fVelocity  < -0.01f)
  380.                 pSurface->fVelocity *= 0.99f;
  381.  
  382.             pSurface->fVelocity += 0.25f * (fDesire - pSurface->fHeight);
  383.             m_fAvgHeight += pSurface->fHeight + pSurface->fVelocity;
  384.  
  385.             pSurface++;
  386.  
  387.             uXN = uX;
  388.             uX  = uXP;
  389.             uXP = (uXP + 1) & WATER_MASK;
  390.         }
  391.         while(uX);
  392.  
  393.         uYN = uY0;
  394.         uY0 = uYP;
  395.         uYP = (uYP + WATER_SIZE) & (WATER_MASK << WATER_SHIFT);
  396.     }
  397.     while(uY0);
  398.  
  399.     m_fAvgHeight /= (float) m_uVertices;
  400.  
  401.  
  402.  
  403.  
  404.     // Calculate surface normals
  405.     WATER_VERTEX *pVertices, *pVertex, *pVertexLim;
  406.  
  407.     D3DXVECTOR3 vec;
  408.     D3DXVECTOR3 vecP, vecN;
  409.  
  410.     if(FAILED(hr = m_pvbVertices->Lock(0, m_uVertices * sizeof(WATER_VERTEX), (BYTE **) &pVertices, 0)))
  411.         return hr;
  412.     
  413.     pVertex = pVertices;
  414.     pVertexLim = pVertex + m_uVertices;
  415.     pSurface = m_pSurface;
  416.  
  417.     float fInc = m_fSize / (float) (WATER_SIZE - 1);
  418.     float fZ = m_fSize * -0.5f;
  419.  
  420.     uYN  = WATER_AREA - WATER_SIZE;
  421.     uY0  = 0;
  422.     uYP  = WATER_SIZE;
  423.  
  424.     do
  425.     {
  426.         float fX = m_fSize * -0.5f;
  427.  
  428.         uXN  = WATER_SIZE - 1;
  429.         uX   = 0;
  430.         uXP  = 1;
  431.  
  432.         do
  433.         {
  434.             // Update position and normal
  435.             vecP.x = fX;
  436.             vecP.y = pSurface->fHeight = pSurface->fHeight + pSurface->fVelocity - m_fAvgHeight;
  437.             vecP.z = fZ;
  438.  
  439.             float f;
  440.             f = m_pSurface[uXN + uYN].fHeight - m_pSurface[uXP + uYP].fHeight; vecN.x = vecN.z = f;           
  441.             f = m_pSurface[uX  + uYN].fHeight - m_pSurface[uX  + uYP].fHeight; vecN.z += f;
  442.             f = m_pSurface[uXP + uYN].fHeight - m_pSurface[uXN + uYP].fHeight; vecN.x -= f; vecN.z += f;
  443.             f = m_pSurface[uXN + uY0].fHeight - m_pSurface[uXP + uY0].fHeight; vecN.x += f;
  444.  
  445.             vecN.y = 1.0f;
  446.             D3DXVec3Normalize(&vecN, &vecN);
  447.  
  448.             pSurface++;
  449.  
  450.  
  451.             // Update texture coords and diffuse based upon refraction
  452.             D3DXVec3Subtract(&vec, &vecPos, &vecP);
  453.             D3DXVec3Normalize(&vec, &vec);
  454.  
  455.             WATER_REFRACT *pRefract;
  456.             pRefract = m_pRefract + f2i(D3DXVec3Dot(&vec, &vecN) * 255.0f);
  457.  
  458.             pVertex->m_vecPos = vecP;
  459.             pVertex->m_vecNormal = vecN;
  460.             pVertex->m_dwDiffuse = pRefract->dwDiffuse;
  461.  
  462.  
  463.             // Bowl
  464.             D3DXVECTOR3 vecD;
  465.             vecD = (vecN * pRefract->fRefract + vec) * pRefract->fRefractNorm;
  466.             vecP.y -= WATER_SPHERE_HEIGHT;
  467.  
  468.             float fC = D3DXVec3Dot(&vecP, &vecP) - WATER_SPHERE_RADIUS2;
  469.  
  470.             if(fC < 0.0f)
  471.             {
  472.                 float fB = D3DXVec3Dot(&vecD, &vecP) * 2.0f;
  473.                 float fD = fB * fB - 4.0f * fC;
  474.                 float fScale = (-fB + sqrtf(fD)) * 0.5f;
  475.  
  476.                 pVertex->m_vecTex.x = (vecD.x * fScale + vecP.x) * m_fScaleTex + 0.5f;
  477.                 pVertex->m_vecTex.y = (vecD.z * fScale + vecP.z) * m_fScaleTex + 0.5f;
  478.             }
  479.             else
  480.             {
  481.                 pVertex->m_vecTex.x = vecP.x * m_fScaleTex + 0.5f;
  482.                 pVertex->m_vecTex.y = vecP.z * m_fScaleTex + 0.5f;
  483.             }
  484.  
  485.  
  486.             pVertex++;
  487.             fX += fInc;
  488.  
  489.             uXN = uX;
  490.             uX  = uXP;
  491.             uXP = (uXP + 1) & WATER_MASK;
  492.         }
  493.         while(uX);
  494.  
  495.         fZ += fInc;
  496.  
  497.         uYN = uY0;
  498.         uY0 = uYP;
  499.         uYP = (uYP + WATER_SIZE) & (WATER_MASK << WATER_SHIFT);
  500.     }
  501.     while(uY0);
  502.  
  503.  
  504.  
  505.     // Calculate caustics
  506.     if(bCalcCaustics)
  507.     {
  508.         CAUSTICS_VERTEX *pCaustics, *pCaustic;
  509.  
  510.         if(FAILED(hr = m_pvbCaustics->Lock(0, m_uVertices * sizeof(CAUSTICS_VERTEX), (BYTE **) &pCaustics, 0)))
  511.             return hr;
  512.  
  513.  
  514.         #define TABLE_SIZE 8
  515.         static DWORD Table[TABLE_SIZE];
  516.         if(!Table[0])
  517.         {
  518.             for(UINT u = 0; u < TABLE_SIZE; u++)
  519.                 Table[u] = (0x40 / (u + 1)) * 0x00010101;
  520.         }
  521.  
  522.  
  523.         pVertex = pVertices;
  524.         pCaustic = pCaustics;
  525.  
  526.         for(uY = 0; uY < WATER_SIZE; uY++)
  527.         {
  528.             for(uX = 0; uX < WATER_SIZE; uX++)
  529.             {
  530.                 WATER_REFRACT *pRefract;
  531.                 pRefract = m_pRefract + f2i(pVertex->m_vecNormal.y * 255.0f);
  532.  
  533.  
  534.                 // Bowl
  535.                 D3DXVECTOR3 vecD, vecP;
  536.                 vecD = (pVertex->m_vecNormal * pRefract->fRefract + vecLight) * pRefract->fRefractNorm;
  537.                 vecP = pVertex->m_vecPos;
  538.                 vecP.y -= WATER_SPHERE_HEIGHT;
  539.  
  540.                 float fC = D3DXVec3Dot(&vecP, &vecP) - WATER_SPHERE_RADIUS2;
  541.  
  542.                 if(fC < 0.0f)
  543.                 {
  544.                     float fB = D3DXVec3Dot(&vecD, &vecP) * 2.0f;
  545.                     float fD = fB * fB - 4.0f * fC;
  546.                     float fScale = (-fB + sqrtf(fD)) * 0.5f;
  547.  
  548.                     pCaustic->m_vecPos.x = vecD.x * fScale + vecP.x;
  549.                     pCaustic->m_vecPos.y = 0.0f;
  550.                     pCaustic->m_vecPos.z = vecD.z * fScale + vecP.z;
  551.                 }
  552.                 else
  553.                 {
  554.                     pCaustic->m_vecPos.x = vecP.x;
  555.                     pCaustic->m_vecPos.y = 0.0f;
  556.                     pCaustic->m_vecPos.z = vecP.z;
  557.                 }
  558.  
  559.  
  560.                 if(uX && uY)
  561.                 {
  562.                     float fArea;
  563.                     fArea = (pCaustic[-WATER_SIZE - 1].m_vecPos.x - pCaustic->m_vecPos.x) *
  564.                             (pCaustic[-WATER_SIZE    ].m_vecPos.z - pCaustic->m_vecPos.z) -
  565.                             (pCaustic[-WATER_SIZE - 1].m_vecPos.z - pCaustic->m_vecPos.z) *
  566.                             (pCaustic[-WATER_SIZE    ].m_vecPos.x - pCaustic->m_vecPos.x);
  567.  
  568.                     if(fArea < 0.0f)
  569.                         fArea = -fArea;
  570.  
  571.                     UINT u = f2i(fArea * fArea * 4.0f);
  572.                     pCaustic->m_dwDiffuse = u < TABLE_SIZE ? Table[u] : 0;
  573.                 }
  574.  
  575.                 pCaustic++;
  576.                 pVertex++;
  577.             }
  578.  
  579.             pCaustic[-WATER_SIZE].m_dwDiffuse = pCaustic[-1].m_dwDiffuse;
  580.         }
  581.  
  582.  
  583.         for(uX = 0; uX < WATER_SIZE; uX++)
  584.         {
  585.             pCaustics[uX].m_dwDiffuse = pCaustics[uX + (WATER_AREA - WATER_SIZE)].m_dwDiffuse;
  586.         }
  587.  
  588.         m_pvbCaustics->Unlock();
  589.     }
  590.  
  591.  
  592.     m_pvbVertices->Unlock();
  593.     return S_OK;
  594. }
  595.  
  596.     
  597. HRESULT 
  598. CWater::DrawCaustics()
  599. {
  600.     HRESULT hr;
  601.  
  602.     if(FAILED(hr = m_pDevice->SetVertexShader(CAUSTICS_FVF)))
  603.         return hr;
  604.  
  605.     if(FAILED(hr = m_pDevice->SetStreamSource(0, m_pvbCaustics, sizeof(CAUSTICS_VERTEX))))
  606.         return hr;
  607.  
  608.     if(FAILED(hr = m_pDevice->SetIndices(m_pibIndices, 0)))
  609.         return hr;
  610.  
  611.     if(FAILED(hr = m_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, m_uVertices, 0, m_uIndices -2)))
  612.         return hr;
  613.  
  614.     return S_OK;
  615. }
  616.  
  617. HRESULT
  618. CWater::DrawSurface()
  619. {
  620.     HRESULT hr;
  621.  
  622.     if(FAILED(hr = m_pDevice->SetStreamSource(0, m_pvbVertices, sizeof(WATER_VERTEX))))
  623.         return hr;
  624.  
  625.     if(FAILED(hr = m_pDevice->SetIndices(m_pibIndices, 0)))
  626.         return hr;
  627.  
  628.     if(FAILED(hr = m_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, m_uVertices, 0, m_uIndices -2)))
  629.         return hr;
  630.  
  631.     return S_OK;
  632. }
  633.  
  634.